#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <Includes.h>
#include <DRV_EC600S.h>
#include <DRV_EC600S_Sock.h>
#include <DRV_EC600S_Event.h>

T_MUTEX sockMux;
static ST_SOCKET sock[SOCK_MAX];

T_MUTEX tailq_rx_mux;
TAILQ_HEAD(,data_rx_entry) tailq_rx_head=TAILQ_HEAD_INITIALIZER(tailq_rx_head);
T_MUTEX tailq_tx_mux;
TAILQ_HEAD(,data_tx_entry) tailq_tx_head=TAILQ_HEAD_INITIALIZER(tailq_tx_head);

/**
@brief sock初始化
@return 0成功，非0失败
**/
int Ec600sSockInit()
{
    int i;

    MUTEX_CREATE(tailq_rx_mux);
	TAILQ_INIT(&tailq_rx_head);
    MUTEX_CREATE(tailq_tx_mux);
	TAILQ_INIT(&tailq_tx_head);
    MUTEX_CREATE(sockMux);

    //套接字初始化
    for(i=0;i<SOCK_MAX;i++)
    {
        sock[i].state=SS_FREE;
        memset(&sock[i].local,0,sizeof(EC600S_ADDR));
        memset(&sock[i].to,0,sizeof(EC600S_ADDR));
        sock[i].sndto=OSOCK_SNDTIMEO;
        sock[i].rcvto=OSOCK_RCVTIMEO;
        sock[i].sndbuf=OSOCK_SNDBUF;
        sock[i].rcvbuf=OSOCK_RCVBUF;
        sock[i].protocol=0;
    }

    return 0;
}

/**
@brief 更新套接字状态
@param s 套接字描述符
@param st 套接字状态
@return 0成功，非0失败
**/
int Ec600sSockStSet(int s, socket_state st)
{
    MUTEX_LOCK(sockMux, MUTEX_WAIT_ALWAYS);
    sock[s].state=st;
    MUTEX_UNLOCK(sockMux);
    return 0;
}

/**
@brief 查询套接字结构体内容
@param s 套接字描述符
@return 套接字结构体内容
**/
ST_SOCKET SOCK(int s)
{
    ST_SOCKET sc;

    MUTEX_LOCK(sockMux, MUTEX_WAIT_ALWAYS);
    sc=sock[s];
    MUTEX_UNLOCK(sockMux);
    return sc;
}

/**
@brief ec600s重启更新套接字组状态
@param st 套接字状态
@return 0成功，非0失败
**/
int Ec600sSockStUpdate()
{
    int i;
    //1.连接/正在连接更新到未连接,2.正在断开更新到未分配
    MUTEX_LOCK(sockMux, MUTEX_WAIT_ALWAYS);
    for(i=0;i<SOCK_MAX;i++)
    {
        if(sock[i].state==SS_CONNECTING
            ||sock[i].state==SS_CONNECTED)
            sock[i].state=SS_DISCONNECTING;
    }
    MUTEX_UNLOCK(sockMux);
    return 0;
}

/**
@brief 调用EC600s AT+QIOPEN打开套接字
@param s 套接字描述符
@param to 目的地址
@param local 本地地址
@return 0成功，-1非法套接字, -2打开套接字失败, -3网络异常,-4场景未初始化
**/
int Ec600sSockOpen(int s, EC600S_ADDR *to, EC600S_ADDR *local)
{
    int ret=0;

    if(SOCK(s).state!=SS_UNCONNECTED)
        return -1;

    ret=EC600S_SOCK_OPEN_EVENT_DO(s, SOCK(s).type, to, local, EVENT_WAIT_DEFAULT);
    if(ret!=0)
        return -2;

    MUTEX_LOCK(sockMux, MUTEX_WAIT_ALWAYS);
    sock[s].state=SS_CONNECTING;
    MUTEX_UNLOCK(sockMux);

    return 0;
}

/**
@brief 调用EC600s AT+QICLOSE关闭套接字
@param s 套接字描述符
@return 0成功，-1非法套接字
**/
int Ec600sSockClose(int s)
{
    int ret;

    if(SOCK(s).state==SS_FREE)
        return -1;
    ret=EC600S_SOCK_CLOSE_EVENT_DO(s,EVENT_WAIT_DEFAULT);
    if(ret!=0)
        return ret;

    MUTEX_LOCK(sockMux, MUTEX_WAIT_ALWAYS);
    sock[s].state=SS_FREE;
    MUTEX_UNLOCK(sockMux);

    return 0;
}

/**
@brief 套接字URC数据接收回调处理函数
@param sock 套接字描述符
@param data 接收数据
@param length 接收数据长度
@return 0成功，非0失败
**/
int Ec600sSockUrcCallback(int s, U8 data[], int length)
{
    ST_DATA_RX_ENTRY *entry;
    int rcvcnt=0;

    MUTEX_LOCK(tailq_rx_mux, MUTEX_WAIT_ALWAYS);
    TAILQ_FOREACH(entry, &tailq_rx_head, elements)
    {
        if(entry->sock==s)
            rcvcnt++;
    }
    if(rcvcnt<SOCK(s).rcvbuf)
    {
        entry=(ST_DATA_RX_ENTRY *)malloc(sizeof(ST_DATA_RX_ENTRY));
        if(entry!=NULL)
        {
            entry->sock=s;
            entry->len=length;
            entry->tick=OppTickCountGet();
            entry->data=(U8 *)malloc(length);
            if(entry->data!=NULL)
            {
                memcpy(entry->data,data,length);
                TAILQ_INSERT_TAIL(&tailq_rx_head,entry,elements);
            }
        }
    }
    MUTEX_UNLOCK(tailq_rx_mux);
    return 0;
}

/**
@brief RX缓存数据超时处理
@param
@return
**/
int Ec600sSockRxTimeout()
{
    ST_DATA_RX_ENTRY *item,*tmp_item;

    MUTEX_LOCK(tailq_rx_mux, MUTEX_WAIT_ALWAYS);
    for(item = TAILQ_FIRST(&tailq_rx_head); item != NULL; item = tmp_item)
    {
        if(OppTickCountGet() - item->tick > SOCK(item->sock).rcvto)
        {
            //删除一个元素
            TAILQ_REMOVE(&tailq_rx_head, item, elements);
            //释放不需要的内存单元
            free(item->data);
            free(item);
            break;
        }
        tmp_item = TAILQ_NEXT(item, elements);
    }
    MUTEX_UNLOCK(tailq_rx_mux);

    return 0;
}

/**
@brief TX缓存数据超时处理
@param
@return
**/
int Ec600sSockTxTimeout()
{
    ST_DATA_TX_ENTRY *item,*tmp_item;

    MUTEX_LOCK(tailq_tx_mux, MUTEX_WAIT_ALWAYS);
    for(item = TAILQ_FIRST(&tailq_tx_head); item != NULL; item = tmp_item)
    {
        if(OppTickCountGet() - item->tick > SOCK(item->sock).sndto)
        {
            //删除一个元素
            TAILQ_REMOVE(&tailq_tx_head, item, elements);
            //释放不需要的内存单元
            free(item->data);
            free(item);
            break;
        }
        tmp_item = TAILQ_NEXT(item, elements);
    }
    MUTEX_UNLOCK(tailq_tx_mux);
    return 0;
}


/**
@brief 接收数据长度
@param s 套接字
@param buf 接收缓存
@param len 接收缓存大小
@param flags 标志位.0非阻塞,1阻塞
@param from 接收源地址
@param addrlen 接收源地址长度
@return 返回值接收数据长度
**/
static int Ec600sReceive(int s, char *buf, int len, int flags, EC600S_ADDR *from, int *addrlen)
{
    ST_DATA_RX_ENTRY *entry,*tmp_entry;
    int rlen=0;
    U32 stick[SOCK_MAX];

    stick[s]=OppTickCountGet();

    while(1)
    {
        MUTEX_LOCK(tailq_rx_mux, MUTEX_WAIT_ALWAYS);
        for(entry = TAILQ_FIRST(&tailq_rx_head); entry != NULL; entry = tmp_entry)
        {
            if(entry->sock==s && (NULL==from?1:memcmp(from,&entry->from,sizeof(EC600S_ADDR))==0))
            {
                if(entry->len>len)
                    rlen=len;
                else
                    rlen=entry->len;
                memcpy(buf,entry->data,rlen);
                TAILQ_REMOVE(&tailq_rx_head,entry,elements);
                free(entry->data);
                free(entry);
                break;
            }
            tmp_entry = TAILQ_NEXT(entry, elements);
        }
        MUTEX_UNLOCK(tailq_rx_mux);
        if(rlen!=0)
        {
            break;
        }
        if(flags==0)
        {
            break;
        }
        if(OppTickCountGet()-stick[s] > SOCK(s).rcvto)
        {
            break;
        }
    }
    return rlen;
}

/**
@brief 发送循环,运行在ec600s任务不能直接调用event接口
@param
@return
**/
int Ec600sTxLoop(void)
{
    ST_DATA_TX_ENTRY *item,*tmp_item;
    EC600S_ADDR zero={0};
    int ret=0;

    MUTEX_LOCK(tailq_tx_mux, MUTEX_WAIT_ALWAYS);
    for(item = TAILQ_FIRST(&tailq_tx_head); item != NULL; item = tmp_item)
    {
        //连接允许发送
        if(SOCK(item->sock).state==SS_CONNECTED)
        {
            if(SOCK(item->sock).protocol==0)
            {
                if(memcmp(&item->to,&zero,sizeof(EC600S_ADDR))==0)
                {
                    ret = Ec600sDataSend(item->sock, EN_DATA_TYPE_STR, item->data, item->len);
                }
                else
                {
                    //TODO:指定目的地址发送
                }
            }
            else
            {
                if(memcmp(&item->to,&zero,sizeof(EC600S_ADDR))==0)
                {
                    ret = Ec600sDataSend(item->sock, EN_DATA_TYPE_HEX, item->data, item->len);
                }
                else
                {
                    //TODO:指定目的地址发送
                }
            }
            //发送成功
            if(ret==0)
            {
                //删除一个元素
                TAILQ_REMOVE(&tailq_tx_head, item, elements);
                //释放不需要的内存单元
                free(item->data);
                free(item);
                break;
            }
        }
        //发送超时
        if(OppTickCountGet() - item->tick > SOCK(item->sock).sndto)
        {
            //删除一个元素
            TAILQ_REMOVE(&tailq_tx_head, item, elements);
            //释放不需要的内存单元
            free(item->data);
            free(item);
            break;
        }
        tmp_item = TAILQ_NEXT(item, elements);
    }
    MUTEX_UNLOCK(tailq_tx_mux);
    return 0;
}

/**
@brief 创建套接字
@param af 协议族
@param type 协议类型
@param protocol 附加协议.0.字符型数据,1.hex数据
@return 分配的套接字ID,-1无空闲套接字
**/
int Ec600sSocket( int af, int type, int protocol)
{
    int i;

    //分配未使用的套接字
    MUTEX_LOCK(sockMux, MUTEX_WAIT_ALWAYS);
    for(i=0;i<SOCK_MAX;i++)
    {
        if(sock[i].state==SS_FREE)
        {
            sock[i].state=SS_UNCONNECTED;
            memset(&sock[i].local,0,sizeof(EC600S_ADDR));
            memset(&sock[i].to,0,sizeof(EC600S_ADDR));
            sock[i].sndto=OSOCK_SNDTIMEO;
            sock[i].rcvto=OSOCK_RCVTIMEO;
            sock[i].sndbuf=OSOCK_SNDBUF;
            sock[i].rcvbuf=OSOCK_RCVBUF;
            sock[i].protocol=protocol;
            MUTEX_UNLOCK(sockMux);
            return i;
        }
    }
    MUTEX_UNLOCK(sockMux);
    return -1;
}

/**
@brief 绑定本地端口
@param s 套接字描述符
@param addr 本地地址
@param addrlen 地址长度
@return 0成功,-1套接字未分配，-2端口被占用
**/
int Ec600sBind(int s, const EC600S_ADDR *addr, int addrlen)
{
    int i;

    if(SOCK(s).state==SS_FREE
        ||SOCK(s).state==SS_DISCONNECTING)
        return -1;

    for(i=0;i<SOCK_MAX;i++)
    {
        if(addr->port!=0 && SOCK(s).local.port==addr->port)
            return -2;
    }
    MUTEX_LOCK(sockMux, MUTEX_WAIT_ALWAYS);
    memcpy(&sock[s].local,addr,addrlen);
    MUTEX_UNLOCK(sockMux);
    return 0;
}


/**
@brief tcp客户端连接服务器
@param s 套接字描述符
@param addr 服务器地址
@param addrlen 地址长度
@return -1.非法套接字
**/
int Ec600sConnect(int s, const EC600S_ADDR *addr, int addrlen)
{
    if(sock[s].state==SS_FREE
        ||sock[s].state==SS_DISCONNECTING)
        return -1;

    MUTEX_LOCK(sockMux, MUTEX_WAIT_ALWAYS);
    memcpy(&sock[s].to,addr,addrlen);
    MUTEX_UNLOCK(sockMux);

    return 0;
}

/**
@brief TCP服务端调用,开始监听
@param s 套接字描述符
@param backlog
@return 0成功,非0失败
**/
int Ec600sListen(int s, int backlog)
{
    return 0;
}

/**
@brief TCP服务端调用,接收TCP客户端的连接
@param s 套接字描述符
@param addr 地址
@param addrlen 地址长度
@return 0成功,非0失败
**/
int Ec600sAccept(int s, EC600S_ADDR *addr, int *addrlen)
{
    return 0;
}

/**
@brief 关闭套接字关闭连接
@param s 套接字描述符
@return 0成功，-1非法套接字
**/
int Ec600sClose(int s)
{
    ST_DATA_RX_ENTRY *item,*tmp_item;
    ST_DATA_TX_ENTRY *txitem,*tmp_txitem;

    //清空接收缓存
    MUTEX_LOCK(tailq_rx_mux, MUTEX_WAIT_ALWAYS);
    for(item = TAILQ_FIRST(&tailq_rx_head); item != NULL; item = tmp_item)
    {
        tmp_item = TAILQ_NEXT(item, elements);

        if(item->sock==s)
        {
            //删除一个元素
            TAILQ_REMOVE(&tailq_rx_head, item, elements);
            //释放不需要的内存单元
            free(item->data);
            free(item);
        }
    }
    MUTEX_UNLOCK(tailq_rx_mux);

    //清空发送缓存
    MUTEX_LOCK(tailq_tx_mux, MUTEX_WAIT_ALWAYS);
    for(txitem = TAILQ_FIRST(&tailq_tx_head); txitem != NULL; txitem = tmp_txitem)
    {
        if(OppTickCountGet() - txitem->tick > SOCK(txitem->sock).sndto)
        {
            //删除一个元素
            TAILQ_REMOVE(&tailq_tx_head, txitem, elements);
            //释放不需要的内存单元
            free(txitem->data);
            free(txitem);
        }
        tmp_txitem = TAILQ_NEXT(txitem, elements);
    }
    MUTEX_UNLOCK(tailq_tx_mux);

    return Ec600sSockClose(s);
}

/**
@brief 关闭套接字关闭连接
@param s 套接字描述符
@param buf 发送数据
@param len 发送数据长度
@return >=0接收数据长度,<0错误码
**/
int Ec600sRecv(int s, char *buf, int len, int flags)
{
    return Ec600sReceive(s,buf,len,flags,NULL,0);
}

/**
@brief TCP调用
@param s 套接字描述符
@param buf 发送数据
@param len 发送数据长度
@param flags 调用执行方式.0:不阻塞,1:阻塞
@return >=0发送字节数，-1.非法套接字,-2.open失败,-3.sndbuf满,-4.发送超时,-5.内存申请失败,-6.网络断开
**/
int Ec600sSend(int s, char *buf, int len, int flags)
{
    return Ec600sSendto(s,buf,len,flags,NULL,0);
}

/**
@brief UDP调用
@param s 套接字描述符
@param buf 接收缓存
@param len 接收缓存长度
@param flags 调用执行方式.0:不阻塞,1:阻塞
@param from 对端地址
@param addrlen 地址长度
@return >=0发送字节数，<0错误
**/
int Ec600sRecvfrom(int s, char *buf, int len, int flags, EC600S_ADDR *from, int *addrlen)
{
    return Ec600sReceive(s,buf,len,flags,from,addrlen);
}

/**
@brief UDP调用
@param s 套接字描述符
@param buf 发送数据
@param len 发送数据长度
@param flags 调用执行方式.0:不阻塞,1:阻塞
@param addr 服务器地址
@param addrlen 地址长度
@return >=0发送字节数，-1.非法套接字,-2.open失败,-3.sndbuf满,-4.发送超时,-5.内存申请失败,-6.网络断开
**/
int Ec600sSendto(int s, char *buf, int len, int flags, EC600S_ADDR *to, int addrlen)
{
    ST_DATA_TX_ENTRY *entry;
    int ret;
    int sndcnt=0;
    int stick[SOCK_MAX]={0};
    EC600S_ADDR to_addr,local;

    if(SOCK(s).state==SS_FREE)
        return -1;

    if(SOCK(s).state==SS_DISCONNECTING)
        return -6;

    //套接字状态判断
    if(SOCK(s).state==SS_UNCONNECTED)
    {
        //OPEN
        if(to==NULL)
        {
            to_addr=SOCK(s).to;
            local=SOCK(s).local;
            ret=Ec600sSockOpen(s,&to_addr,&local);
        }
        else
        {
            local=SOCK(s).local;
            ret=Ec600sSockOpen(s,to,&local);
        }
        if(ret!=0)
            return -2;
    }

    while(1)
    {
        MUTEX_LOCK(tailq_tx_mux, MUTEX_WAIT_ALWAYS);
        TAILQ_FOREACH(entry, &tailq_tx_head, elements)
        {
            if(entry->sock==s)
                sndcnt++;
        }
        MUTEX_UNLOCK(tailq_tx_mux);

        //非阻塞
        if(flags==0)
        {
            if(sndcnt>SOCK(s).sndbuf)
                return -3;
            else
                break;
        }
        //阻塞模式
        else
        {
            if(stick[s]==0)
                stick[s]=OppTickCountGet();
            if(sndcnt<=SOCK(s).sndbuf)
                break;
            if(OppTickCountGet()-stick[s] > SOCK(s).sndto)
            {
                return -4;
            }
        }
    }

    entry=(ST_DATA_TX_ENTRY *)malloc(sizeof(ST_DATA_TX_ENTRY));
    if(entry==NULL)
    {
        return -1;
    }

    memset(entry,0,sizeof(ST_DATA_TX_ENTRY));
    entry->sock=s;
    entry->len=len;
    entry->tick=OppTickCountGet();
    entry->data=(U8 *)malloc(len);
    if(entry->data==NULL)
    {
        free(entry);
        return -1;
    }

    memcpy(entry->data,(U8 *)buf,len);

    if(to!=NULL)
        memcpy(&entry->to,to,addrlen);

    MUTEX_LOCK(tailq_tx_mux, MUTEX_WAIT_ALWAYS);
    TAILQ_INSERT_TAIL(&tailq_tx_head,entry,elements);
    MUTEX_UNLOCK(tailq_tx_mux);

    return len;
}

/**
@brief 设置套接字选项
@param s 套接字描述符
@param level 设置级别
@param optname 选项名称
@param optval 选项值
@param optlen 选项值长度
@return >=0发送字节数，<0错误
**/
int Ec600sSetsockopt(int s, int level, int optname, const void *optval, int optlen)
{
    int ret=0;

    if(SOCK(s).state==SS_FREE)
        return -1;

    if(level==OSOL_SOCKET)
    {
        MUTEX_LOCK(sockMux, MUTEX_WAIT_ALWAYS);
        if(optname==OSO_RCVTIMEO)
            sock[s].rcvto=*(int *)optval;
        else if(optname==OSO_SNDTIMEO)
            sock[s].sndto=*(int *)optval;
        else if(optname==OSO_RCVBUF)
            sock[s].rcvbuf=*(int *)optval;
        else if(optname==OSO_SNDBUF)
            sock[s].sndbuf=*(int *)optval;
        else
            ret = -2;
        MUTEX_UNLOCK(sockMux);
    }
    return ret;
}

/**
@brief 套接字主函数
@return 0成功，非0失败
**/
int Ec600sSockLoop(void)
{
    Ec600sSockRxTimeout();
    Ec600sSockTxTimeout();
    Ec600sTxLoop();
    return 0;
}

